﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Xml.Linq;
using System.ComponentModel;
using ThreeByte.ActiveDeck.AddIn.Config.Properties;

namespace ThreeByte.ActiveDeck.AddIn.Content.Controls
{
    public enum EnabledState { On, Off, Toggle };

    [TypeConverter(typeof(NavigationActionConverter))]
    [Editor(typeof(ActionEditor), typeof(System.Drawing.Design.UITypeEditor))]
    public class NavigationAction : DependencyObject
    {
        
        public NavigationAction() { }

        public static readonly DependencyProperty NextProperty = DependencyProperty.Register("Next",
            typeof(bool), typeof(NavigationAction), new PropertyMetadata(NextChanged));

        public bool Next {
            get {
                return (bool)GetValue(NextProperty);
            }
            set {
                SetValue(NextProperty, value);
            }
        }

        private static void NextChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) {
            NavigationAction action = (NavigationAction)obj;
            if(action.Next) {
                action.Submit = false;
                action.Jump = false;
                action.Save = false;
                action.Back = false;
                action.Text = "NEXT";
            }
        }

        public static readonly DependencyProperty BackProperty = DependencyProperty.Register("Back",
            typeof(bool), typeof(NavigationAction), new PropertyMetadata(BackChanged));

        public bool Back {
            get {
                return (bool)GetValue(BackProperty);
            }
            set {
                SetValue(BackProperty, value);
            }
        }

        private static void BackChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) {
            NavigationAction action = (NavigationAction)obj;
            if(action.Back) {
                action.Submit = false;
                action.Jump = false;
                action.Save = false;
                action.Next = false;
                action.Text = "BACK";
            }
        }


        public static readonly DependencyProperty SubmitProperty = DependencyProperty.Register("Submit",
            typeof(bool), typeof(NavigationAction), new PropertyMetadata(true, SubmitChanged));

        public bool Submit {
            get {
                return (bool)GetValue(SubmitProperty);
            }
            set {
                SetValue(SubmitProperty, value);
            }
        }

        private static void SubmitChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) {
            NavigationAction action = (NavigationAction)obj;
            if(action.Submit) {
                action.Next = false;
                action.Jump = false;
                action.Save = false;
                action.Back = false;
                action.Text = "SUBMIT";
            }
        }

        public static readonly DependencyProperty SaveProperty = DependencyProperty.Register("Save",
            typeof(bool), typeof(NavigationAction), new PropertyMetadata(true, SaveChanged));

        public bool Save {
            get {
                return (bool)GetValue(SaveProperty);
            }
            set {
                SetValue(SaveProperty, value);
            }
        }

        private static void SaveChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) {
            NavigationAction action = (NavigationAction)obj;
            if(action.Save) {
                action.Next = false;
                action.Submit = false;
                action.Jump = false;
                action.Back = false;
                action.Text = "SAVE";
            }
        }


        public static readonly DependencyProperty JumpProperty = DependencyProperty.Register("Jump",
            typeof(bool), typeof(NavigationAction), new PropertyMetadata(JumpChanged));

        public bool Jump {
            get {
                return (bool)GetValue(JumpProperty);
            }
            set {
                SetValue(JumpProperty, value);
            }
        }

        private static void JumpChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) {
            NavigationAction action = (NavigationAction)obj;
            if(action.Jump) {
                action.Next = false;
                action.Submit = false;
                action.Save = false;
                action.Back = false;
                action.Text = string.Format("{0}.{1}", action.Section, action.Page);
            }
        }


        public static readonly DependencyProperty SectionProperty = DependencyProperty.Register("Section",
            typeof(int), typeof(NavigationAction));

        public int Section {
            get {
                return (int)GetValue(SectionProperty);
            }
            set {
                SetValue(SectionProperty, value);
            }
        }

        public static readonly DependencyProperty PageProperty = DependencyProperty.Register("Page",
            typeof(int), typeof(NavigationAction));

        public int Page {
            get {
                return (int)GetValue(PageProperty);
            }
            set {
                SetValue(PageProperty, value);
            }
        }

        public static readonly DependencyProperty JumpOffsetProperty = DependencyProperty.Register("JumpOffset",
            typeof(bool), typeof(NavigationAction));

        public bool JumpOffset {
            get {
                return (bool)GetValue(JumpOffsetProperty);
            }
            set {
                SetValue(JumpOffsetProperty, value);
            }
        }

        public static readonly DependencyProperty HOffsetProperty = DependencyProperty.Register("HOffset",
            typeof(int), typeof(NavigationAction));

        public int HOffset {
            get {
                return (int)GetValue(HOffsetProperty);
            }
            set {
                SetValue(HOffsetProperty, value);
            }
        }

        public static readonly DependencyProperty VOffsetProperty = DependencyProperty.Register("VOffset",
            typeof(int), typeof(NavigationAction));

        public int VOffset {
            get {
                return (int)GetValue(VOffsetProperty);
            }
            set {
                SetValue(VOffsetProperty, value);
            }
        }

        public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text",
            typeof(string), typeof(NavigationAction), new PropertyMetadata(@"SUBMIT",TextChanged));

        public string Text {
            get {
                return (string)GetValue(TextProperty);
            }
            set {
                SetValue(TextProperty, value);
            }
        }

        private static void TextChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) {
            //NavigationAction action = (NavigationAction)obj;
            //if(action.Next) {
            //    action.Submit = false;
            //    action.Jump = false;
            //}
        }

        public static readonly DependencyProperty LayerProperty = DependencyProperty.Register("Layer",
            typeof(bool), typeof(NavigationAction), new PropertyMetadata(LayerChanged));

        public bool Layer {
            get {
                return (bool)GetValue(LayerProperty);
            }
            set {
                SetValue(LayerProperty, value);
            }
        }

        private static void LayerChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) {
            NavigationAction action = (NavigationAction)obj;
            if(action.Layer) {
                action.Jump = false;
                action.Next = false;
                action.Submit = false;
                action.Save = false;
                action.Back = false;
                action.Text = string.Format("Layer {0} [{1}]", action.LayerTarget, action.State);
            }
        }

        public static readonly DependencyProperty LayerTargetProperty = DependencyProperty.Register("LayerTarget",
            typeof(int), typeof(NavigationAction));

        public int LayerTarget {
            get {
                return (int)GetValue(LayerTargetProperty);
            }
            set {
                SetValue(LayerTargetProperty, value);
            }
        }

        public static readonly DependencyProperty StateProperty = DependencyProperty.Register("State",
            typeof(EnabledState), typeof(NavigationAction), new FrameworkPropertyMetadata(EnabledState.Toggle));

        public EnabledState State {
            get {
                return (EnabledState)GetValue(StateProperty);
            }
            set {
                SetValue(StateProperty, value);
            }
        }


        public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command",
            typeof(bool), typeof(NavigationAction), new PropertyMetadata(CommandChanged));

        public bool Command {
            get {
                return (bool)GetValue(CommandProperty);
            }
            set {
                SetValue(CommandProperty, value);
            }
        }

        private static void CommandChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) {
            NavigationAction action = (NavigationAction)obj;
            if(action.Command) {
                action.Submit = false;
                action.Jump = false;
                action.Save = false;
                action.Next = false;
                action.Back = false;
                action.Text = string.Empty;
            }
        }

        public static readonly DependencyProperty CommandDataProperty = DependencyProperty.Register("CommandData",
            typeof(string), typeof(NavigationAction));

        public string CommandData {
            get {
                return (string)GetValue(CommandDataProperty);
            }
            set {
                SetValue(CommandDataProperty, value);
            }
        }

        #region Serialization
        private static readonly XNamespace ns = Service.ServiceConfiguration.NAMESPACE;

        public XElement ToXml() {
            XElement node = new XElement(ns + "Action");
            if(Next) {
                node.Add(new XAttribute("Type", "Next"));
            } else if(Back) {
                node.Add(new XAttribute("Type", "Back"));
            } else if(Submit) {
                node.Add(new XAttribute("Type", "Submit"));
            } else if(Save) {
                node.Add(new XAttribute("Type", "Save"));
            } else if(Jump) {
                node.Add(new XAttribute("Type", "GoTo"));
                node.Add(new XAttribute("Section", Section));
                node.Add(new XAttribute("Page", Page));
                if(JumpOffset) {
                    node.Add(new XAttribute("HOffset", HOffset));
                    node.Add(new XAttribute("VOffset", VOffset));
                }
            } else if(Layer) {
                node.Add(new XAttribute("Type", "Layer"));
                node.Add(new XAttribute("Target", LayerTarget));
                node.Add(new XAttribute("State", State));
            } else if(Command) {
                node.Add(new XAttribute("Type", "Command"));
                node.Add(new XAttribute("Method", "publish"));
                node.Add(new XElement(ns + "Data", CommandData));
            }

            return node;
        }

        public static NavigationAction FromXml(XElement node) {
            NavigationAction action = new NavigationAction();
            string typeString = node.Attribute("Type").Value;
            action.Next = (typeString == "Next");
            action.Back = (typeString == "Back");
            action.Submit = (typeString == "Submit");
            action.Save = (typeString == "Save");
            if(typeString == "GoTo") {
                action.Section = int.Parse(node.Attribute("Section").Value);
                action.Page = int.Parse(node.Attribute("Page").Value);
                if(node.Attribute("HOffset") != null) {
                    action.HOffset = int.Parse(node.Attribute("HOffset").Value);
                    action.JumpOffset = true;
                }
                if(node.Attribute("VOffset") != null) {
                    action.VOffset = int.Parse(node.Attribute("VOffset").Value);
                    action.JumpOffset = true;
                }
            }
            action.Jump = (typeString == "GoTo");
            if(typeString == "Layer") {
                action.LayerTarget = int.Parse(node.Attribute("Target").Value);
                action.State = (EnabledState)(Enum.Parse(typeof(EnabledState), node.Attribute("State").Value));
            }
            action.Layer = (typeString == "Layer");

            action.Command  = (typeString == "Command");
            if(action.Command && (node.Element(ns + "Data") != null)) {
                action.CommandData = node.Element(ns + "Data").Value;
            }

            if(action.Submit) {
                action.Text = "SUBMIT";
            }
            if(action.Save) {
                action.Text = "SAVE";
            }
            return action;
        }

        public override string ToString() {
            if(Next) {
                return @"Next";
            } else if(Back) {
                return @"Back";
            } else if(Submit) {
                return @"Submit";
            } else if(Save) {
                return @"Save";
            } else if(Jump) {
                return string.Format("GoTo: [{0}/{1}]", Section, Page);
            } else if(Layer) {
                return string.Format("Layer {0} {1}", LayerTarget, State);
            } else if(Command) {
                return "Command";
            }

            return base.ToString();
        }

        #endregion

    }


    internal class NavigationActionConverter : TypeConverter
    {

        public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) {

            if(destinationType == typeof(string) && value is NavigationAction) {

                NavigationAction action = (NavigationAction)value;
                action.ToString();
            }
            
            return base.ConvertTo(context, culture, value, destinationType);
        }


    }
}
